package main

import (
	"log"
	"sync"
	"time"
)

func producer(mu *sync.Mutex, cond *sync.Cond, queue *[]int) {
	for i := 1; i <= 3; i++ { // 生产 3 个数据后退出
		mu.Lock() // 加锁：操作队列前保护共享资源

		// 往队列添加数据（条件“队列可写”此处简化，实际可判断队列是否满）
		*queue = append(*queue, i)
		log.Printf("生产者：添加数据 %d，当前队列：%v", i, queue)

		// 通知等待的消费者（条件“队列非空”已满足）
		//cond.Signal() //只通知一个
		cond.Broadcast() //通知所有等待的 goroutine

		mu.Unlock()                 // 手动解锁（避免 defer 延迟导致通知不及时）
		time.Sleep(1 * time.Second) // 模拟生产耗时
	}
}

func consumer(mu *sync.Mutex, cond *sync.Cond, queue *[]int, id int) {
	for {
		mu.Lock()
		// 关键：用 for 循环判断条件
		for len(*queue) == 0 {
			cond.Wait() //  释放锁并阻塞,就在这里等待，cond.singal 被通知后重新获取锁并继续
		}

		// 取走队列头部数据（操作共享资源）
		data := (*queue)[0] //消费一个数据
		*queue = (*queue)[1:]
		log.Printf("消费者 %d：取走数据 %d，剩余队列：%v", id, data, queue)

		mu.Unlock()
		time.Sleep(500 * time.Millisecond) // 模拟消费耗时
	}
}

func main() {
	// 1. 创建条件变量：需要绑定一个互斥锁（保证条件判断和操作的原子性）
	mu := &sync.Mutex{}
	cond := sync.NewCond(mu)

	// 共享队列（生产者往这里加数据，消费者从这里取数据）
	queue := make([]int, 0, 5)

	// 2. 生产者：每隔 1 秒往队列加数据，然后通知消费者
	go producer(mu, cond, &queue)

	// 3. 消费者 1：等待队列“非空”，然后取走数据
	go consumer(mu, cond, &queue, 1)

	// 4. 消费者 2：逻辑和消费者 1 一致
	go consumer(mu, cond, &queue, 2)

	// 主线程阻塞（避免程序提前退出）
	time.Sleep(13 * time.Second)

}
